#include "Config.h"
#include "DBAccount.h"
#include "DBPlayer.h"
#include "DBRoom.h"
#include "DBGameReport.h"
#include "TimeUtil.h"
#include "../GameConfig.h"
#include "Base64.h"
#include "DBCache.h"
#include "DBDataExecHelper.h"
#include "DBWorker.h"
#include "../Server.h"
#include "../Player.h"

Player * DBCache::loginPlayer(const std::string& unionid, const std::string& nick, const std::string& headImgUrl, UInt8 sex)
{
	DBAccount * dbAccount = getAccount(unionid);
	if (dbAccount == nullptr)
	{
		//create a new account
		dbAccount = new(std::nothrow) DBAccount();
		ASSERT(dbAccount != nullptr);
		dbAccount->_id = genAccountID();
		dbAccount->_card = gameConfig.getInitCard();
		dbAccount->_unionid = unionid;
		CBase64::Encode(reinterpret_cast<const unsigned char *>(nick.c_str()), nick.length(), dbAccount->_nick);
		dbAccount->_promoter = 0;
		dbAccount->_accType = 0;
		dbAccount->_icon = headImgUrl;
		_accounts.insert(std::make_pair(unionid, dbAccount));
		saveAccount(dbAccount);
	}
	else
	{
		CBase64::Encode(reinterpret_cast<const unsigned char *>(nick.c_str()), nick.length(), dbAccount->_nick);
		dbAccount->_icon = headImgUrl;
		DB().PushPlatUpdateData("UPDATE `account` SET `nick` = '%s', `icon` = '%s' WHERE `id` = %"I64_FMT"u", dbAccount->_nick.c_str(), dbAccount->_icon.c_str(), dbAccount->_id);
	}
	//
	DBPlayer * dbPlayer = getPlayer(dbAccount->_id);
	if (dbPlayer == nullptr)
	{
		//create a new player
		dbPlayer = new(std::nothrow) DBPlayer();
		ASSERT(dbPlayer != nullptr);
		dbPlayer->_id = dbAccount->_id;
		dbPlayer->_nick = dbAccount->_nick;
		dbPlayer->_sex = sex;
		dbPlayer->_headIcon = headImgUrl;
		dbPlayer->_rid = 0;
		dbPlayer->_loginTime = TimeUtil::Now();
		dbPlayer->_createdTime = dbPlayer->_loginTime;
		dbPlayer->_account = dbAccount;
		savePlayer(dbPlayer);
	}
	else
	{
		dbPlayer->_nick = dbAccount->_nick;
		dbPlayer->_sex = sex;
		dbPlayer->_headIcon = headImgUrl;
		DB().PushObjectUpdateData("UPDATE `player` SET `nick` = '%s', `sex` = %u, `headIcon` = '%s' WHERE `id` = %"I64_FMT"u", dbPlayer->_nick.c_str(), dbPlayer->_sex, dbPlayer->_headIcon.c_str(), dbPlayer->_id);
	}
	//
	Player * pl = new(std::nothrow) Player();
	PlayerData& pd = pl->getPlayerData();
	pd._id = dbPlayer->_id;
	pd._nick = nick;
	pd._sex = sex;
	pd._headIcon = headImgUrl;
	pd._promoter = dbAccount->_promoter;
	pd._rid = dbPlayer->_rid;
	pd._reports = dbPlayer->buildGameReports();
	pd._loginTime = dbPlayer->_loginTime;
	pd._createdTime = dbPlayer->_createdTime;
	//
	pl->setCard(dbAccount->_card);
	pl->setDBAccount(dbAccount);
	pl->setDBPlayer(dbPlayer);
	return pl;
}


bool DBCache::createRoom(Player * pl, UInt32 rid, UInt32 turn, UInt8 huType, UInt8 zx, UInt8 hzlz, UInt8 qxd, UInt8 zn)
{
	DBRoom * dbRoom = new(std::nothrow) DBRoom();
	dbRoom->_id = rid;
	dbRoom->_ownerId = pl->getId();
	dbRoom->_turn = turn;
	dbRoom->_remainTurn = turn;
	dbRoom->_huType = huType;
	dbRoom->_zx = zx;
	dbRoom->_hzlz = hzlz;
	dbRoom->_qxd = qxd;
	dbRoom->_zn = zn;
	dbRoom->_members.push_back(DBRoomMember(pl->getDBPlayer(), 0, 1));
	dbRoom->_createdTime = TimeUtil::Now();
	saveRoom(dbRoom);
	pl->setRid(rid);
	enterRoomPlayer(pl->getDBPlayer(), rid);
	return true;
}

bool DBCache::createRoom(DBPlayer * dbPlayer, UInt32 rid, UInt32 turn, UInt8 huType, UInt8 zx, UInt8 hzlz, UInt8 qxd, UInt8 zn)
{

	//TODO : if player is online  !!!
	return true;
}

bool DBCache::joinRoom(Player * pl, UInt32 rid)
{
	DBRoom * dbRoom = getRoom(rid);
	if (dbRoom == nullptr)
		return false;
	//
	UInt8 poss0[] = { 1, 2, 3, 4 };
	std::set<UInt8> poss(poss0, poss0 + 4);
	for (size_t i = 0; i < dbRoom->_members.size(); ++i)
	{
		if (dbRoom->_members[i]._dbPlayer->_id == pl->getId())
			return true;
		poss.erase(dbRoom->_members[i]._pos);
	}
	//
	if (dbRoom->_members.size() >= 4)
		return false;
	DBRoomMember drm;
	drm._dbPlayer = pl->getDBPlayer();
	drm._pos = poss.empty() ? 0 : *poss.begin();
	drm._score = 0;
	dbRoom->_members.push_back(drm);
	pl->setRid(rid);
	enterRoom(pl, rid);
	updateRoomMembers(dbRoom);
	return true;
}

bool DBCache::joinRoom(DBPlayer * dbPlayer, UInt32 rid)
{
	DBRoom * dbRoom = getRoom(rid);
	if (dbRoom == nullptr)
		return false;
	//
	UInt8 poss0[] = { 1, 2, 3, 4 };
	std::set<UInt8> poss(poss0, poss0 + 4);
	for (size_t i = 0; i < dbRoom->_members.size(); ++i)
	{
		if (dbRoom->_members[i]._dbPlayer->_id == dbPlayer->_id)
			return true;
		poss.erase(dbRoom->_members[i]._pos);
	}
	//
	if (dbRoom->_members.size() >= 4)
		return false;
	DBRoomMember drm;
	drm._dbPlayer = dbPlayer;
	drm._pos = poss.empty() ? 0 : *poss.begin();
	drm._score = 0;
	dbRoom->_members.push_back(drm);
	dbPlayer->_rid = rid;
	enterRoomPlayer(dbPlayer, rid);
	updateRoomMembers(dbRoom);
	return true;
}
